/*
*
==============================================================================
*  Name        : 
*  Part of     : Omen Game Engine
*  Description : 
*  Version     : 1.0
*
*  Copyright (c) 2013 Lauri Kortevaara.
* 
==============================================================================
*/

#pragma once

/// Omen Headers
#include <IOmenMesh.h>
#include <IOmenModel.h>

#include <OmenEventHandler.h>
#include <OmenFrameEvent.h>

/// STL Headers
#include <vector>

namespace Omen
{
    class Mesh : public Omen::IMesh, public Omen::EventHandler
    {
    public:
        #define GUID_OMEN_MESH "C3D3F36C-4D09-405F-AA86-99FD906F63A0"
    public:
        OMEN_API virtual Omen_GUID classId() const { return OMEN_UUID(GUID_OMEN_MESH); }    /// <summary>Defines the class ID</summary>

        OMEN_API Mesh( Omen::IModel* pModel = NULL );
        OMEN_API Mesh( const Mesh& other );
        OMEN_API virtual ~Mesh();

        OMEN_API virtual void setModel( Omen::IModel* pModel );
        OMEN_API virtual Omen::IModel* model() const;

        OMEN_API virtual void render( const IRenderer* pRenderer);                    /// <summary>Render this mesh using given renderer</summary>

        // Scaling
        OMEN_API virtual void scale( Omen::Float& x, Omen::Float& y, Omen::Float& z );
        OMEN_API virtual void setScale( Omen::Float x, Omen::Float y, Omen::Float z );

        // Vertices
        OMEN_API virtual void addVertex( const Omen::IMesh::Vertex& v );
        OMEN_API virtual unsigned long vertexCount() const;
        OMEN_API virtual void getVertices( Omen::IMesh::Vertex* pListVertices, unsigned long& maxSize );
        OMEN_API virtual bool getVertex( unsigned long index, std::vector<IMesh::Vertex>::iterator& iter );

        // Faces
        OMEN_API virtual void addFace( unsigned long p1, unsigned long p2, unsigned long p3 );
        OMEN_API virtual void Mesh::addFace( const Omen::IMesh::Face& face );
        OMEN_API virtual unsigned long faceCount() const;
        OMEN_API virtual void getFaces( Omen::IMesh::Face** pListFaces, unsigned long& maxSize );
        OMEN_API virtual bool getFace( unsigned long index, std::vector<IMesh::Face>::iterator& iter );

        // Normals
        OMEN_API virtual void updateVertexNormals( Omen::Float limitSmoothAngle = 45.0f ); /// Calculate the vertex normals and smoothen edeges
        OMEN_API virtual Omen::Vector3d faceNormal( unsigned long faceIndex ); /// Returns the normal of this face
        OMEN_API virtual Omen::Vector3d faceNormal( const Face& face ); /// Returns the normal of this face


        /// Vertex and index buffers
        OMEN_API virtual void setVertexBufferPtr( void* ptrVertexBuffer );      /// <summary>Set Renderer specific vertex buffer pointer</summary>
        OMEN_API virtual void setIndexBufferPtr( void* ptrIndexBuffer );      /// <summary>Set Renderer specific vertex buffer pointer</summary>

        OMEN_API virtual void* vertexBufferPtr() const;                      /// <summary>Returns the Renderer specific vertex buffer pointer </summary>
        OMEN_API virtual void* indexBufferPtr() const;                       /// <summary>Returns the Renderer specific vertex buffer pointer </summary>

        /// Shaders
        OMEN_API virtual void setVertexShaderPtr( Omen::IShader* ptrVertexShader );    /// <summary>Set the vertex shader pointer</summary>
        OMEN_API virtual Omen::IShader* vertexShaderPtr() const;                        /// <summary>Set the vertex shader pointer</summary>

        // Texture
        OMEN_API virtual void setTexture( Omen::ITexture* pTexture );
        OMEN_API virtual Omen::ITexture* texture() const;

        /// Material
        OMEN_API void setMaterial( Omen::IMaterial* pMaterial );
        OMEN_API Omen::IMaterial*  material( unsigned long faceIndex = -1 ) const;
        
        // Bounding volumes, Sphere and Axis Aligned Bounding Box (AABB) of the mesh
        virtual const Omen::Sphere& boundingSphere() const;
        virtual const Omen::AABB& boundingBox() const;
        virtual void updateBoundingVolumes();

        // Mesh transformation, translation and rotation
        OMEN_API virtual Omen::Matrix4x4 transformation() const;                     /// <summary>Returns the global transformation matrix of the mesh</summary>
        OMEN_API virtual Omen::Vector3d  globalPosition() const;                     /// <summary>Returns the position of the mesh origo in global coordinate space</summary>
        OMEN_API virtual Omen::Vector3d  localPosition() const;                      /// <summary>Returns the position of the mesh in model's/parent's coordinate space</summary>
        OMEN_API virtual Omen::Vector3d center();                                    /// <summary>Returns the center of this mesh in model's/parent's coordinate space</summary>
        OMEN_API virtual void getRotation( Omen::Float& yaw, Omen::Float& pitch, Omen::Float& roll ) const; /// <summary>Returns the yaw,pitch and roll rotation angles of the mesh</summary>
        OMEN_API virtual void setRotation( Omen::Float yaw, Omen::Float pitch, Omen::Float roll ); /// <summary>Sets the yaw, pitch and roll rotation angles of the mesh</summary>
        OMEN_API virtual void rotateY( Omen::Float angle );                          /// <summary>Rotates the mesh around y-axis for given angle</summary>
        OMEN_API virtual void rotateX( Omen::Float angle );                          /// <summary>Rotates the mesh around x-axis for given angle</summary>
        OMEN_API virtual void rotateZ( Omen::Float angle );                          /// <summary>Rotates the mesh around z-axis for given angle</summary>

        OMEN_API virtual void translate( const Omen::Vector3d& v );                  /// <summary>Translate the position of the mesh by given vector</summary>
        OMEN_API virtual void setPosition( const Omen::Vector3d& v );                /// <summary>Set the position of the mesh to given position</summary>

        virtual void centralizeVertices();

        OMEN_API virtual bool hasChanged() const;                                    /// boolean value to indicate whether this mesh has changed since last frame

        /// OMEN Event system
        void OnFrameEvent(const Omen::FrameEvent* event );

    protected:
    private:
        std::vector<Omen::IMesh::Vertex>    m_vertices;
        std::vector<Omen::IMesh::Face>      m_faces;

        void*                               m_ptrVertexBuffer;
        void*                               m_ptrIndexBuffer;

        IShader*                            m_ptrVertexShader;
        ITexture*                           m_pTexture;
        Omen::Vector3d                      m_scaleVector;
        Omen::IModel*                       m_pModel;
        Omen::IMaterial*                    m_pMaterial;

        mutable Matrix4x4                   m_transformation;

        Omen::Float                         m_yaw, m_pitch, m_roll;                                     // yaw, pitch and roll rotation angles

        Omen::AABB                          m_aabb;
        Omen::Sphere                        m_boundingSphere;
        Omen::Vector3d                      m_center;
        mutable bool                        m_bMeshHasChanged;
        bool                                m_bNormalsUpdated;
    };
}